package com.light.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.light.common.utils.R;
import com.light.gulimall.cart.entity.SkuInfoEntity;
import com.light.gulimall.cart.entity.SkuSaleAttrValueEntity;
import com.light.gulimall.cart.exception.InvalidateUserInfoExp;
import com.light.gulimall.cart.feign.ProductRemoteServiceClient;
import com.light.gulimall.cart.interceptor.CartInterceptor;
import com.light.gulimall.cart.service.CartService;
import com.light.gulimall.cart.vo.Cart;
import com.light.gulimall.cart.vo.CartItem;
import com.light.gulimall.cart.vo.UserInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ProductRemoteServiceClient productRemoteServiceClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    public final String CART_PREFIX = "gulimall:cart:";

    @Override
    public CartItem addToCart(Long skuId, Integer num) throws InvalidateUserInfoExp, ExecutionException, InterruptedException {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        //存入redis前先要判断该条记录是否已经存在
        String item = (String) cartOps.get(skuId + "");
        if (item != null) {
            //修改数量
            CartItem cartItem = JSON.parseObject(item, CartItem.class);
            cartItem.setCount(cartItem.getCount() + num);
            cartOps.put(skuId + "", JSON.toJSONString(cartItem));
            return cartItem;
        }


        ObjectMapper objectMapper = new ObjectMapper();
        //组装CartItem信息
        CartItem cartItem = new CartItem();

        CompletableFuture<Void> asyncInfo = CompletableFuture.runAsync(() -> {
            //异步远程调用商品服务查询商品信息
            R info = productRemoteServiceClient.info(skuId);
            LinkedHashMap skuInfo = (LinkedHashMap) info.get("skuInfo");

            SkuInfoEntity skuInfoEntity = objectMapper.convertValue(skuInfo, SkuInfoEntity.class);
            if (skuInfo != null) {
                cartItem.setSkuId(skuId);
                cartItem.setCount(num);
                cartItem.setPrice(skuInfoEntity.getPrice());
                cartItem.setTitle(skuInfoEntity.getSkuTitle());
                cartItem.setCheck(true);
                cartItem.setImage(skuInfoEntity.getSkuDefaultImg());
            }
        }, threadPoolExecutor);

        //异步远程调用商品服务查询销售属性
        CompletableFuture<Void> asyncAttr = CompletableFuture.runAsync(() -> {
                    R attrInfo = productRemoteServiceClient.infoList(skuId);
                    List<LinkedHashMap> infoList = (List<LinkedHashMap>) attrInfo.get("infoList");

                    List<SkuSaleAttrValueEntity> skuSaleAttrValueList = infoList.stream()
                            .map(map -> objectMapper.convertValue(map, SkuSaleAttrValueEntity.class))
                            .collect(Collectors.toList());

                    List<String> skuAttr = skuSaleAttrValueList.stream()
                            .map(skuSaleAttrValueEntity -> skuSaleAttrValueEntity.getAttrName() + ":" + skuSaleAttrValueEntity.getAttrValue())
                            .collect(Collectors.toList());
                    cartItem.setSkuAttr(skuAttr);
                }
                , threadPoolExecutor);

        //等待两个异步任务全部执行完成
        CompletableFuture.allOf(asyncInfo, asyncAttr).get();


        cartOps.put(skuId + "", JSON.toJSONString(cartItem));


        return cartItem;
    }

    @Override
    public CartItem getInfoBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = this.getCartOps();
        String item = (String) cartOps.get(skuId + "");
        return JSON.parseObject(item, CartItem.class);
    }

    @Override
    public Cart getCartListPage() throws ExecutionException, InterruptedException {
        UserInfoVO userInfoVO = CartInterceptor.threadLocal.get();
        if (userInfoVO == null || (userInfoVO.getUserKey() == null && userInfoVO.getUserId() == null)) {
            throw new InvalidateUserInfoExp();
        }
        Cart cart = new Cart();

        String cartKey = null;
        if (userInfoVO.getUserId() != null) {
            //用户购物车
            cartKey = CART_PREFIX + userInfoVO.getUserId();
            //判断临时购物车是否为空
            String userKey = CART_PREFIX + userInfoVO.getUserKey();
            ArrayList<CartItem> cartItems = this.getCartItems(userKey);
            //如果不为空需要添加到用户购物车中
            //合并：查出临时购物车的数据，存入登录购物车
            if (!CollectionUtils.isEmpty(cartItems)) {
                for (CartItem cartItem : cartItems) {
                    //因为现在是登录状态，所以会添加到登录购物车中
                    this.addToCart(cartItem.getSkuId(), cartItem.getCount());
                }
            }
            //清空临时购物车
            this.redisCacheDel(userKey);
            cart.setItems(getCartItems(cartKey));
        }//临时购物车
        else {
            cartKey = CART_PREFIX + userInfoVO.getUserKey();
            ArrayList<CartItem> cartItems = this.getCartItems(cartKey);
            cart.setItems(cartItems);
        }
        return cart;
    }

    @Override
    public void checkItem(Long skuId, Boolean prop) {
        BoundHashOperations<String, Object, Object> cartOps = this.getCartOps();
        String cartItemJson = (String) cartOps.get(skuId + "");
        CartItem cartItem = JSON.parseObject(cartItemJson, CartItem.class);
        cartItem.setCheck(prop);
        cartOps.put(skuId + "", JSON.toJSONString(cartItem));
    }

    @Override
    public void modifyNum(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> cartOps = this.getCartOps();
        String cartItemJson = (String) cartOps.get(skuId + "");
        CartItem cartItem = JSON.parseObject(cartItemJson, CartItem.class);
        cartItem.setCount(num);
        cartOps.put(skuId + "", JSON.toJSONString(cartItem));
    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = this.getCartOps();
        cartOps.delete(skuId + "");
    }

    @Override
    public List<CartItem> getCurrentUserCartItems() {
        UserInfoVO userInfoVO = CartInterceptor.threadLocal.get();

        ArrayList<CartItem> cartItems = this.getCartItems(CART_PREFIX + userInfoVO.getUserId());
        if (!CollectionUtils.isEmpty(cartItems)) {
            //筛选出选中的商品，并且重新计算价格为最新的价格
            return cartItems.stream().filter(CartItem::getCheck).map(cartItem -> {
                        Long skuId = cartItem.getSkuId();
                        //根据skuId查询最新的价格 远程调用product服务
                        BigDecimal price = productRemoteServiceClient.getPrice(skuId);
                        cartItem.setPrice(price);
                        return cartItem;
                    }
            ).collect(Collectors.toList());
        }
        return null;
    }


    /**
     * 清除某个key下的全部缓存
     * @param userKey
     */
    private void redisCacheDel(String userKey) {
        stringRedisTemplate.delete(userKey);
    }

    /**
     * 根据key从redis中获取购物车数据
     * @param cartKey
     * @return
     */
    private ArrayList<CartItem> getCartItems(String cartKey) {
        BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(cartKey);
        Set<Object> keys = operations.keys();
        ArrayList<CartItem> cartItems = new ArrayList<>();
        for (Object key : keys) {
            String cartItemJson = (String) operations.get(key + "");
            CartItem cartItem = JSON.parseObject(cartItemJson, CartItem.class);
            cartItems.add(cartItem);
        }
        return cartItems;
    }

    private BoundHashOperations<String, Object, Object> getCartOps() throws InvalidateUserInfoExp {
        UserInfoVO userInfoVO = CartInterceptor.threadLocal.get();
        if (userInfoVO == null || (userInfoVO.getUserKey() == null && userInfoVO.getUserId() == null)) {
            throw new InvalidateUserInfoExp();
        }
        String cartKey = null;
        if (userInfoVO.getUserId() != null) {
            //用户购物车
            cartKey = CART_PREFIX + userInfoVO.getUserId();
        }//临时购物车
        else {
            cartKey = CART_PREFIX + userInfoVO.getUserKey();
        }

        return stringRedisTemplate.boundHashOps(cartKey);
    }
}
